package sbcc.edu.blackjack;

import java.util.ArrayList;
import java.util.List;
import sbcc.edu.blackjack.utility.XORShiftRandom;

/**
 *
 * Shoe is the collection of cards from which the hands are dealt
 * 
 * Lazy card creation is used,
 * only integers (1-52) are stored until the card is selected
 * then a new card is created and sent to the player's hand
 *
 * The assumption is made that the suit is in the range 0-3 and the rank is in the range 1-13
 * This is necessary for card creation and in particular lazy card creation.
 * 
 * @author Ray Kolbe
 */
public class Shoe
{

    public static final int NUMBER_DECKS = 6;
    public static final int DECK_SIZE = 52;
    public static final int NUMBER_CARDS = DECK_SIZE * NUMBER_DECKS;
    public static final int NUMBER_IN_SUIT = 13;
    public static final int NUMBER_OF_SUITS = 4;
    // random number generator
    private XORShiftRandom rand;
    // array of integers representing cards
    private List<Integer> cards;
    private int numberCardsRemaining;

    /*
     * The constructor initializes the array of cards (integers until the actual Card is created),
     * sets the number of cards (array size for array of integers), and initializes the random number generator.
     */
    public Shoe()
    {
        // When the shoe is created put a value, from 1 to 52 in the list of cards
        cards = new ArrayList<Integer>();
        for (int i = 0; i < NUMBER_CARDS; i++) {
            cards.add(i, i % DECK_SIZE);
        }

        // initialize the size of the list of cards remaining to be dealt
        setNumberCardsRemaining(NUMBER_CARDS);

        // set up the random number generator
        long seed = System.currentTimeMillis();
        rand = new XORShiftRandom(seed);

    }

    // getter for numberCardsRemaining
    public int getNumberCardsRemaining()
    {
        return numberCardsRemaining;
    }

    // setter is private to ensure that the value is never set anywhere but in this code
    private void setNumberCardsRemaining(int NumberCardsRemaining)
    {
        this.numberCardsRemaining = NumberCardsRemaining;
    }

    // setter that is used to decrement numberCardsRemaining
    private void decrementNumberCardsRemaining()
    {
        numberCardsRemaining--;
    }

    /*
     * Since we randomly select from the cards remaining,
     * shuffle is nothing more than resetting the value of the crads remaining
     */
    public void shuffle()
    {
        setNumberCardsRemaining(NUMBER_CARDS);
    }

    /*
     * DrawCard is where a card is randomly selected (via drawCardNumber),  and
     * then a Card object is created and returned
     */
    public Card drawCard()
    {
        int cardValue = drawCardNumber();
        int rank = cardValue % NUMBER_IN_SUIT + 1;
        int suit = cardValue / NUMBER_IN_SUIT;
        Card newCard = new Card(rank, suit);
        return newCard;
    }

    /*
     * drawCardNumber randomly selects a location in the array (of integers 0-51)
     * the value represents a playing card, as there are 52 unique cards in a deck and 6 decks in a shoe.
     * The randomly selected location is from 0 to the numberCardsRemaining (cards not yet dealt).
     * The value found at that location is swapped with the value at numberCardsRemaining.
     * Then numberCardsRemaining is decremented, and Finally, a new Card is created and returned.
     */
    private Integer drawCardNumber()
    {
        int selection = 0;  // Used as the location in the cards array, so will be randomly generated
        int selectionValue = 0; // Value found at the location "selection" in cards
        int lastVal = getNumberCardsRemaining(); // Remaining cards which have not yet been dealt
        Integer aCard; // temporary location when performing the swap
        if (lastVal > 1) {
            selection = rand.nextInt(--lastVal); // "lastVal" number must be positive from zero to the number of cards remaining to be dealt
        }
        /*
         * Swap the values (last card available & randomly selected one)
         * Preserving the randomly selected one in "selectionValue"
         * which is returned by this function
         */
        aCard = cards.get(lastVal);
        selectionValue = cards.set(selection, aCard);
        cards.set(lastVal, selectionValue);
        this.decrementNumberCardsRemaining(); // decrement available array size
        return selectionValue;
    }
}
